Skip to content

Lock built-in JavaScript runtimes - #33

Open
sergeivaskov wants to merge 2 commits into
elixir-volt:masterfrom
sergeivaskov:fix/builtin-runtime-lockfiles
Open

Lock built-in JavaScript runtimes#33
sergeivaskov wants to merge 2 commits into
elixir-volt:masterfrom
sergeivaskov:fix/builtin-runtime-lockfiles

Conversation

@sergeivaskov

Copy link
Copy Markdown

Summary

  • ship package-owned npm_ex lockfiles for the built-in Svelte, Solid, and Tailwind runtimes
  • install exact direct versions through a shared Volt.JS.Runtime.PackageSet
  • include the lockfile digest in named runtime identity and provide a lock update script

Problem

Volt's built-in framework/compiler runtimes currently resolve version ranges independently of an application's package.json and npm.lock. For example, the Svelte plugin requests ^5.0.0, while Tailwind requests ^4.3.0 and *. The runtime installer already supports a package-owned lockfile, but these built-in callers do not pass one, so a fresh build can select a different transitive graph without an application lockfile change.

Design

Volt.JS.Runtime.PackageSet keeps each built-in runtime's exact package set and packaged lockfile together. Both direct installation and named runtime creation use that same lock. Named runtime signatures hash the lock contents rather than depending on a path, so changing a packaged graph cannot silently reuse a runtime created from an older lock.

scripts/update_runtime_locks.exs regenerates all locks, or one selected package set with --only, from the exact versions declared by the owning module.

Verification

  • mix test: 609 tests, 0 failures
  • fresh-cache package-set integration tests install byte-identical packaged locks
  • the built Hex archive contains priv/npm/{svelte,solid,tailwind}.lock
  • two independent clean Ubuntu amd64 consumer builds produced identical runtime locks and production assets

@dannote

dannote commented Aug 11, 2026

Copy link
Copy Markdown
Member

Thanks for working on this! One concern before merging: these lockfiles are tied to registry.npmjs.org, and PackageSet always uses them. Projects configured with a private or corporate npm registry will fail when starting Svelte, Solid, or Tailwind:

** (ArgumentError) npm lockfile security policy does not match current configuration:
.../volt/priv/npm/svelte.lock

Previously, those dependencies were resolved using the project’s configured registry. Could we fall back to normal resolution when the bundled lockfile’s registry policy is incompatible?

@sergeivaskov

Copy link
Copy Markdown
Author

Thanks, good catch. I pushed 84ffe3c to address this.

PackageSet now uses a bundled lock only when its recorded npm_ex policy matches the current configuration. If the policies are incompatible, it omits the bundled lock while retaining the exact direct package versions, so the existing Installer normal-resolution path uses the project configured registry.

This fallback is scoped to bundled package sets. Generic explicit lockfile validation in Installer is unchanged, and callers still cannot replace a package set packages or lockfile.

Added a regression test covering an incompatible private-registry policy. Validation:

  • focused regression: red before the fix, green after it (17 passed)
  • package-set integration: 18 passed
  • full ExUnit suite with the CI Playwright setup: 568 passed
  • format, warnings-as-errors compile, Credo, duplication check, and Dialyzer: passed

The default compatible-policy path still installs the packaged locks without re-resolving.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants